home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / python2.4 / xml / dom / expatbuilder.pyc (.txt) < prev    next >
Python Compiled Bytecode  |  2005-10-18  |  31KB  |  1,018 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.4)
  3.  
  4. '''Facility to use the Expat parser to load a minidom instance
  5. from a string or file.
  6.  
  7. This avoids all the overhead of SAX and pulldom to gain performance.
  8. '''
  9. from xml.dom import xmlbuilder, minidom, Node
  10. from xml.dom import EMPTY_NAMESPACE, EMPTY_PREFIX, XMLNS_NAMESPACE
  11. from xml.parsers import expat
  12. from xml.dom.minidom import _append_child, _set_attribute_node
  13. from xml.dom.NodeFilter import NodeFilter
  14. from xml.dom.minicompat import *
  15. TEXT_NODE = Node.TEXT_NODE
  16. CDATA_SECTION_NODE = Node.CDATA_SECTION_NODE
  17. DOCUMENT_NODE = Node.DOCUMENT_NODE
  18. FILTER_ACCEPT = xmlbuilder.DOMBuilderFilter.FILTER_ACCEPT
  19. FILTER_REJECT = xmlbuilder.DOMBuilderFilter.FILTER_REJECT
  20. FILTER_SKIP = xmlbuilder.DOMBuilderFilter.FILTER_SKIP
  21. FILTER_INTERRUPT = xmlbuilder.DOMBuilderFilter.FILTER_INTERRUPT
  22. theDOMImplementation = minidom.getDOMImplementation()
  23. _typeinfo_map = {
  24.     'CDATA': minidom.TypeInfo(None, 'cdata'),
  25.     'ENUM': minidom.TypeInfo(None, 'enumeration'),
  26.     'ENTITY': minidom.TypeInfo(None, 'entity'),
  27.     'ENTITIES': minidom.TypeInfo(None, 'entities'),
  28.     'ID': minidom.TypeInfo(None, 'id'),
  29.     'IDREF': minidom.TypeInfo(None, 'idref'),
  30.     'IDREFS': minidom.TypeInfo(None, 'idrefs'),
  31.     'NMTOKEN': minidom.TypeInfo(None, 'nmtoken'),
  32.     'NMTOKENS': minidom.TypeInfo(None, 'nmtokens') }
  33.  
  34. class ElementInfo(NewStyle):
  35.     __slots__ = ('_attr_info', '_model', 'tagName')
  36.     
  37.     def __init__(self, tagName, model = None):
  38.         self.tagName = tagName
  39.         self._attr_info = []
  40.         self._model = model
  41.  
  42.     
  43.     def __getstate__(self):
  44.         return (self._attr_info, self._model, self.tagName)
  45.  
  46.     
  47.     def __setstate__(self, state):
  48.         (self._attr_info, self._model, self.tagName) = state
  49.  
  50.     
  51.     def getAttributeType(self, aname):
  52.         for info in self._attr_info:
  53.             if info[1] == aname:
  54.                 t = info[-2]
  55.                 if t[0] == '(':
  56.                     return _typeinfo_map['ENUM']
  57.                 else:
  58.                     return _typeinfo_map[info[-2]]
  59.             t[0] == '('
  60.         
  61.         return minidom._no_type
  62.  
  63.     
  64.     def getAttributeTypeNS(self, namespaceURI, localName):
  65.         return minidom._no_type
  66.  
  67.     
  68.     def isElementContent(self):
  69.         if self._model:
  70.             type = self._model[0]
  71.             return type not in (expat.model.XML_CTYPE_ANY, expat.model.XML_CTYPE_MIXED)
  72.         else:
  73.             return False
  74.  
  75.     
  76.     def isEmpty(self):
  77.         if self._model:
  78.             return self._model[0] == expat.model.XML_CTYPE_EMPTY
  79.         else:
  80.             return False
  81.  
  82.     
  83.     def isId(self, aname):
  84.         for info in self._attr_info:
  85.             if info[1] == aname:
  86.                 return info[-2] == 'ID'
  87.                 continue
  88.         
  89.         return False
  90.  
  91.     
  92.     def isIdNS(self, euri, ename, auri, aname):
  93.         return self.isId((auri, aname))
  94.  
  95.  
  96.  
  97. def _intern(builder, s):
  98.     return builder._intern_setdefault(s, s)
  99.  
  100.  
  101. def _parse_ns_name(builder, name):
  102.     if not ' ' in name:
  103.         raise AssertionError
  104.     parts = name.split(' ')
  105.     intern = builder._intern_setdefault
  106.     if len(parts) == 3:
  107.         (uri, localname, prefix) = parts
  108.         prefix = intern(prefix, prefix)
  109.         qname = '%s:%s' % (prefix, localname)
  110.         qname = intern(qname, qname)
  111.         localname = intern(localname, localname)
  112.     else:
  113.         (uri, localname) = parts
  114.         prefix = EMPTY_PREFIX
  115.         qname = localname = intern(localname, localname)
  116.     return (intern(uri, uri), localname, prefix, qname)
  117.  
  118.  
  119. class ExpatBuilder:
  120.     '''Document builder that uses Expat to build a ParsedXML.DOM document
  121.     instance.'''
  122.     
  123.     def __init__(self, options = None):
  124.         if options is None:
  125.             options = xmlbuilder.Options()
  126.         
  127.         self._options = options
  128.         if self._options.filter is not None:
  129.             self._filter = FilterVisibilityController(self._options.filter)
  130.         else:
  131.             self._filter = None
  132.             self._finish_start_element = id
  133.         self._parser = None
  134.         self.reset()
  135.  
  136.     
  137.     def createParser(self):
  138.         '''Create a new parser object.'''
  139.         return expat.ParserCreate()
  140.  
  141.     
  142.     def getParser(self):
  143.         '''Return the parser object, creating a new one if needed.'''
  144.         if not self._parser:
  145.             self._parser = self.createParser()
  146.             self._intern_setdefault = self._parser.intern.setdefault
  147.             self._parser.buffer_text = True
  148.             self._parser.ordered_attributes = True
  149.             self._parser.specified_attributes = True
  150.             self.install(self._parser)
  151.         
  152.         return self._parser
  153.  
  154.     
  155.     def reset(self):
  156.         '''Free all data structures used during DOM construction.'''
  157.         self.document = theDOMImplementation.createDocument(EMPTY_NAMESPACE, None, None)
  158.         self.curNode = self.document
  159.         self._elem_info = self.document._elem_info
  160.         self._cdata = False
  161.  
  162.     
  163.     def install(self, parser):
  164.         '''Install the callbacks needed to build the DOM into the parser.'''
  165.         parser.StartDoctypeDeclHandler = self.start_doctype_decl_handler
  166.         parser.StartElementHandler = self.first_element_handler
  167.         parser.EndElementHandler = self.end_element_handler
  168.         parser.ProcessingInstructionHandler = self.pi_handler
  169.         if self._options.entities:
  170.             parser.EntityDeclHandler = self.entity_decl_handler
  171.         
  172.         parser.NotationDeclHandler = self.notation_decl_handler
  173.         if self._options.comments:
  174.             parser.CommentHandler = self.comment_handler
  175.         
  176.         if self._options.cdata_sections:
  177.             parser.StartCdataSectionHandler = self.start_cdata_section_handler
  178.             parser.EndCdataSectionHandler = self.end_cdata_section_handler
  179.             parser.CharacterDataHandler = self.character_data_handler_cdata
  180.         else:
  181.             parser.CharacterDataHandler = self.character_data_handler
  182.         parser.ExternalEntityRefHandler = self.external_entity_ref_handler
  183.         parser.XmlDeclHandler = self.xml_decl_handler
  184.         parser.ElementDeclHandler = self.element_decl_handler
  185.         parser.AttlistDeclHandler = self.attlist_decl_handler
  186.  
  187.     
  188.     def parseFile(self, file):
  189.         '''Parse a document from a file object, returning the document
  190.         node.'''
  191.         parser = self.getParser()
  192.         first_buffer = True
  193.         
  194.         try:
  195.             while None:
  196.                 buffer = file.read(16 * 1024)
  197.                 if not buffer:
  198.                     break
  199.                 
  200.                 if first_buffer and self.document.documentElement:
  201.                     self._setup_subset(buffer)
  202.                 
  203.                 first_buffer = False
  204.             parser.Parse('', True)
  205.         except ParseEscape:
  206.             pass
  207.  
  208.         doc = self.document
  209.         self.reset()
  210.         self._parser = None
  211.         return doc
  212.  
  213.     
  214.     def parseString(self, string):
  215.         '''Parse a document from a string, returning the document node.'''
  216.         parser = self.getParser()
  217.         
  218.         try:
  219.             parser.Parse(string, True)
  220.             self._setup_subset(string)
  221.         except ParseEscape:
  222.             pass
  223.  
  224.         doc = self.document
  225.         self.reset()
  226.         self._parser = None
  227.         return doc
  228.  
  229.     
  230.     def _setup_subset(self, buffer):
  231.         '''Load the internal subset if there might be one.'''
  232.         if self.document.doctype:
  233.             extractor = InternalSubsetExtractor()
  234.             extractor.parseString(buffer)
  235.             subset = extractor.getSubset()
  236.             self.document.doctype.internalSubset = subset
  237.         
  238.  
  239.     
  240.     def start_doctype_decl_handler(self, doctypeName, systemId, publicId, has_internal_subset):
  241.         doctype = self.document.implementation.createDocumentType(doctypeName, publicId, systemId)
  242.         doctype.ownerDocument = self.document
  243.         self.document.childNodes.append(doctype)
  244.         self.document.doctype = doctype
  245.         if self._filter and self._filter.acceptNode(doctype) == FILTER_REJECT:
  246.             self.document.doctype = None
  247.             del self.document.childNodes[-1]
  248.             doctype = None
  249.             self._parser.EntityDeclHandler = None
  250.             self._parser.NotationDeclHandler = None
  251.         
  252.         if has_internal_subset:
  253.             if doctype is not None:
  254.                 doctype.entities._seq = []
  255.                 doctype.notations._seq = []
  256.             
  257.             self._parser.CommentHandler = None
  258.             self._parser.ProcessingInstructionHandler = None
  259.             self._parser.EndDoctypeDeclHandler = self.end_doctype_decl_handler
  260.         
  261.  
  262.     
  263.     def end_doctype_decl_handler(self):
  264.         if self._options.comments:
  265.             self._parser.CommentHandler = self.comment_handler
  266.         
  267.         self._parser.ProcessingInstructionHandler = self.pi_handler
  268.         if not self._elem_info or self._filter:
  269.             self._finish_end_element = id
  270.         
  271.  
  272.     
  273.     def pi_handler(self, target, data):
  274.         node = self.document.createProcessingInstruction(target, data)
  275.         _append_child(self.curNode, node)
  276.         if self._filter and self._filter.acceptNode(node) == FILTER_REJECT:
  277.             self.curNode.removeChild(node)
  278.         
  279.  
  280.     
  281.     def character_data_handler_cdata(self, data):
  282.         childNodes = self.curNode.childNodes
  283.         if self._cdata:
  284.             if self._cdata_continue and childNodes[-1].nodeType == CDATA_SECTION_NODE:
  285.                 childNodes[-1].appendData(data)
  286.                 return None
  287.             
  288.             node = self.document.createCDATASection(data)
  289.             self._cdata_continue = True
  290.         elif childNodes and childNodes[-1].nodeType == TEXT_NODE:
  291.             node = childNodes[-1]
  292.             value = node.data + data
  293.             d = node.__dict__
  294.             d['data'] = d['nodeValue'] = value
  295.             return None
  296.         else:
  297.             node = minidom.Text()
  298.             d = node.__dict__
  299.             d['data'] = d['nodeValue'] = data
  300.             d['ownerDocument'] = self.document
  301.         _append_child(self.curNode, node)
  302.  
  303.     
  304.     def character_data_handler(self, data):
  305.         childNodes = self.curNode.childNodes
  306.         if childNodes and childNodes[-1].nodeType == TEXT_NODE:
  307.             node = childNodes[-1]
  308.             d = node.__dict__
  309.             d['data'] = d['nodeValue'] = node.data + data
  310.             return None
  311.         
  312.         node = minidom.Text()
  313.         d = node.__dict__
  314.         d['data'] = d['nodeValue'] = node.data + data
  315.         d['ownerDocument'] = self.document
  316.         _append_child(self.curNode, node)
  317.  
  318.     
  319.     def entity_decl_handler(self, entityName, is_parameter_entity, value, base, systemId, publicId, notationName):
  320.         if is_parameter_entity:
  321.             return None
  322.         
  323.         if not self._options.entities:
  324.             return None
  325.         
  326.         node = self.document._create_entity(entityName, publicId, systemId, notationName)
  327.         if value is not None:
  328.             child = self.document.createTextNode(value)
  329.             node.childNodes.append(child)
  330.         
  331.         self.document.doctype.entities._seq.append(node)
  332.         if self._filter and self._filter.acceptNode(node) == FILTER_REJECT:
  333.             del self.document.doctype.entities._seq[-1]
  334.         
  335.  
  336.     
  337.     def notation_decl_handler(self, notationName, base, systemId, publicId):
  338.         node = self.document._create_notation(notationName, publicId, systemId)
  339.         self.document.doctype.notations._seq.append(node)
  340.         if self._filter and self._filter.acceptNode(node) == FILTER_ACCEPT:
  341.             del self.document.doctype.notations._seq[-1]
  342.         
  343.  
  344.     
  345.     def comment_handler(self, data):
  346.         node = self.document.createComment(data)
  347.         _append_child(self.curNode, node)
  348.         if self._filter and self._filter.acceptNode(node) == FILTER_REJECT:
  349.             self.curNode.removeChild(node)
  350.         
  351.  
  352.     
  353.     def start_cdata_section_handler(self):
  354.         self._cdata = True
  355.         self._cdata_continue = False
  356.  
  357.     
  358.     def end_cdata_section_handler(self):
  359.         self._cdata = False
  360.         self._cdata_continue = False
  361.  
  362.     
  363.     def external_entity_ref_handler(self, context, base, systemId, publicId):
  364.         return 1
  365.  
  366.     
  367.     def first_element_handler(self, name, attributes):
  368.         if self._filter is None and not (self._elem_info):
  369.             self._finish_end_element = id
  370.         
  371.         self.getParser().StartElementHandler = self.start_element_handler
  372.         self.start_element_handler(name, attributes)
  373.  
  374.     
  375.     def start_element_handler(self, name, attributes):
  376.         node = self.document.createElement(name)
  377.         _append_child(self.curNode, node)
  378.         self.curNode = node
  379.         if attributes:
  380.             for i in range(0, len(attributes), 2):
  381.                 a = minidom.Attr(attributes[i], EMPTY_NAMESPACE, None, EMPTY_PREFIX)
  382.                 value = attributes[i + 1]
  383.                 d = a.childNodes[0].__dict__
  384.                 d['data'] = d['nodeValue'] = value
  385.                 d = a.__dict__
  386.                 d['value'] = d['nodeValue'] = value
  387.                 d['ownerDocument'] = self.document
  388.                 _set_attribute_node(node, a)
  389.             
  390.         
  391.         if node is not self.document.documentElement:
  392.             self._finish_start_element(node)
  393.         
  394.  
  395.     
  396.     def _finish_start_element(self, node):
  397.         if self._filter:
  398.             if node is self.document.documentElement:
  399.                 return None
  400.             
  401.             filt = self._filter.startContainer(node)
  402.             if filt == FILTER_REJECT:
  403.                 Rejecter(self)
  404.             elif filt == FILTER_SKIP:
  405.                 Skipper(self)
  406.             else:
  407.                 return None
  408.             self.curNode = node.parentNode
  409.             node.parentNode.removeChild(node)
  410.             node.unlink()
  411.         
  412.  
  413.     
  414.     def end_element_handler(self, name):
  415.         curNode = self.curNode
  416.         self.curNode = curNode.parentNode
  417.         self._finish_end_element(curNode)
  418.  
  419.     
  420.     def _finish_end_element(self, curNode):
  421.         info = self._elem_info.get(curNode.tagName)
  422.         if info:
  423.             self._handle_white_text_nodes(curNode, info)
  424.         
  425.         if self._filter:
  426.             if curNode is self.document.documentElement:
  427.                 return None
  428.             
  429.             if self._filter.acceptNode(curNode) == FILTER_REJECT:
  430.                 self.curNode.removeChild(curNode)
  431.                 curNode.unlink()
  432.             
  433.         
  434.  
  435.     
  436.     def _handle_white_text_nodes(self, node, info):
  437.         if self._options.whitespace_in_element_content or not info.isElementContent():
  438.             return None
  439.         
  440.         L = []
  441.         for child in node.childNodes:
  442.             if child.nodeType == TEXT_NODE and not child.data.strip():
  443.                 L.append(child)
  444.                 continue
  445.         
  446.         for child in L:
  447.             node.removeChild(child)
  448.         
  449.  
  450.     
  451.     def element_decl_handler(self, name, model):
  452.         info = self._elem_info.get(name)
  453.         if info is None:
  454.             self._elem_info[name] = ElementInfo(name, model)
  455.         elif not info._model is None:
  456.             raise AssertionError
  457.         info._model = model
  458.  
  459.     
  460.     def attlist_decl_handler(self, elem, name, type, default, required):
  461.         info = self._elem_info.get(elem)
  462.         if info is None:
  463.             info = ElementInfo(elem)
  464.             self._elem_info[elem] = info
  465.         
  466.         info._attr_info.append([
  467.             None,
  468.             name,
  469.             None,
  470.             None,
  471.             default,
  472.             0,
  473.             type,
  474.             required])
  475.  
  476.     
  477.     def xml_decl_handler(self, version, encoding, standalone):
  478.         self.document.version = version
  479.         self.document.encoding = encoding
  480.         if standalone >= 0:
  481.             if standalone:
  482.                 self.document.standalone = True
  483.             else:
  484.                 self.document.standalone = False
  485.         
  486.  
  487.  
  488. _ALLOWED_FILTER_RETURNS = (FILTER_ACCEPT, FILTER_REJECT, FILTER_SKIP)
  489.  
  490. class FilterVisibilityController(NewStyle):
  491.     '''Wrapper around a DOMBuilderFilter which implements the checks
  492.     to make the whatToShow filter attribute work.'''
  493.     __slots__ = ('filter',)
  494.     
  495.     def __init__(self, filter):
  496.         self.filter = filter
  497.  
  498.     
  499.     def startContainer(self, node):
  500.         mask = self._nodetype_mask[node.nodeType]
  501.         if self.filter.whatToShow & mask:
  502.             val = self.filter.startContainer(node)
  503.             if val == FILTER_INTERRUPT:
  504.                 raise ParseEscape
  505.             
  506.             if val not in _ALLOWED_FILTER_RETURNS:
  507.                 raise ValueError, 'startContainer() returned illegal value: ' + repr(val)
  508.             
  509.             return val
  510.         else:
  511.             return FILTER_ACCEPT
  512.  
  513.     
  514.     def acceptNode(self, node):
  515.         mask = self._nodetype_mask[node.nodeType]
  516.         if self.filter.whatToShow & mask:
  517.             val = self.filter.acceptNode(node)
  518.             if val == FILTER_INTERRUPT:
  519.                 raise ParseEscape
  520.             
  521.             if val == FILTER_SKIP:
  522.                 parent = node.parentNode
  523.                 for child in node.childNodes[:]:
  524.                     parent.appendChild(child)
  525.                 
  526.                 return FILTER_REJECT
  527.             
  528.             if val not in _ALLOWED_FILTER_RETURNS:
  529.                 raise ValueError, 'acceptNode() returned illegal value: ' + repr(val)
  530.             
  531.             return val
  532.         else:
  533.             return FILTER_ACCEPT
  534.  
  535.     _nodetype_mask = {
  536.         Node.ELEMENT_NODE: NodeFilter.SHOW_ELEMENT,
  537.         Node.ATTRIBUTE_NODE: NodeFilter.SHOW_ATTRIBUTE,
  538.         Node.TEXT_NODE: NodeFilter.SHOW_TEXT,
  539.         Node.CDATA_SECTION_NODE: NodeFilter.SHOW_CDATA_SECTION,
  540.         Node.ENTITY_REFERENCE_NODE: NodeFilter.SHOW_ENTITY_REFERENCE,
  541.         Node.ENTITY_NODE: NodeFilter.SHOW_ENTITY,
  542.         Node.PROCESSING_INSTRUCTION_NODE: NodeFilter.SHOW_PROCESSING_INSTRUCTION,
  543.         Node.COMMENT_NODE: NodeFilter.SHOW_COMMENT,
  544.         Node.DOCUMENT_NODE: NodeFilter.SHOW_DOCUMENT,
  545.         Node.DOCUMENT_TYPE_NODE: NodeFilter.SHOW_DOCUMENT_TYPE,
  546.         Node.DOCUMENT_FRAGMENT_NODE: NodeFilter.SHOW_DOCUMENT_FRAGMENT,
  547.         Node.NOTATION_NODE: NodeFilter.SHOW_NOTATION }
  548.  
  549.  
  550. class FilterCrutch(NewStyle):
  551.     __slots__ = ('_builder', '_level', '_old_start', '_old_end')
  552.     
  553.     def __init__(self, builder):
  554.         self._level = 0
  555.         self._builder = builder
  556.         parser = builder._parser
  557.         self._old_start = parser.StartElementHandler
  558.         self._old_end = parser.EndElementHandler
  559.         parser.StartElementHandler = self.start_element_handler
  560.         parser.EndElementHandler = self.end_element_handler
  561.  
  562.  
  563.  
  564. class Rejecter(FilterCrutch):
  565.     __slots__ = ()
  566.     
  567.     def __init__(self, builder):
  568.         FilterCrutch.__init__(self, builder)
  569.         parser = builder._parser
  570.         for name in ('ProcessingInstructionHandler', 'CommentHandler', 'CharacterDataHandler', 'StartCdataSectionHandler', 'EndCdataSectionHandler', 'ExternalEntityRefHandler'):
  571.             setattr(parser, name, None)
  572.         
  573.  
  574.     
  575.     def start_element_handler(self, *args):
  576.         self._level = self._level + 1
  577.  
  578.     
  579.     def end_element_handler(self, *args):
  580.         if self._level == 0:
  581.             parser = self._builder._parser
  582.             self._builder.install(parser)
  583.             parser.StartElementHandler = self._old_start
  584.             parser.EndElementHandler = self._old_end
  585.         else:
  586.             self._level = self._level - 1
  587.  
  588.  
  589.  
  590. class Skipper(FilterCrutch):
  591.     __slots__ = ()
  592.     
  593.     def start_element_handler(self, *args):
  594.         node = self._builder.curNode
  595.         self._old_start(*args)
  596.         if self._builder.curNode is not node:
  597.             self._level = self._level + 1
  598.         
  599.  
  600.     
  601.     def end_element_handler(self, *args):
  602.         if self._level == 0:
  603.             self._builder._parser.StartElementHandler = self._old_start
  604.             self._builder._parser.EndElementHandler = self._old_end
  605.             self._builder = None
  606.         else:
  607.             self._level = self._level - 1
  608.             self._old_end(*args)
  609.  
  610.  
  611. _FRAGMENT_BUILDER_INTERNAL_SYSTEM_ID = 'http://xml.python.org/entities/fragment-builder/internal'
  612. _FRAGMENT_BUILDER_TEMPLATE = '<!DOCTYPE wrapper\n  %%s [\n  <!ENTITY fragment-builder-internal\n    SYSTEM "%s">\n%%s\n]>\n<wrapper %%s\n>&fragment-builder-internal;</wrapper>' % _FRAGMENT_BUILDER_INTERNAL_SYSTEM_ID
  613.  
  614. class FragmentBuilder(ExpatBuilder):
  615.     '''Builder which constructs document fragments given XML source
  616.     text and a context node.
  617.  
  618.     The context node is expected to provide information about the
  619.     namespace declarations which are in scope at the start of the
  620.     fragment.
  621.     '''
  622.     
  623.     def __init__(self, context, options = None):
  624.         if context.nodeType == DOCUMENT_NODE:
  625.             self.originalDocument = context
  626.             self.context = context
  627.         else:
  628.             self.originalDocument = context.ownerDocument
  629.             self.context = context
  630.         ExpatBuilder.__init__(self, options)
  631.  
  632.     
  633.     def reset(self):
  634.         ExpatBuilder.reset(self)
  635.         self.fragment = None
  636.  
  637.     
  638.     def parseFile(self, file):
  639.         '''Parse a document fragment from a file object, returning the
  640.         fragment node.'''
  641.         return self.parseString(file.read())
  642.  
  643.     
  644.     def parseString(self, string):
  645.         '''Parse a document fragment from a string, returning the
  646.         fragment node.'''
  647.         self._source = string
  648.         parser = self.getParser()
  649.         doctype = self.originalDocument.doctype
  650.         ident = ''
  651.         if doctype:
  652.             if not doctype.internalSubset:
  653.                 pass
  654.             subset = self._getDeclarations()
  655.             if doctype.publicId:
  656.                 ident = 'PUBLIC "%s" "%s"' % (doctype.publicId, doctype.systemId)
  657.             elif doctype.systemId:
  658.                 ident = 'SYSTEM "%s"' % doctype.systemId
  659.             
  660.         else:
  661.             subset = ''
  662.         nsattrs = self._getNSattrs()
  663.         document = _FRAGMENT_BUILDER_TEMPLATE % (ident, subset, nsattrs)
  664.         
  665.         try:
  666.             parser.Parse(document, 1)
  667.         except:
  668.             self.reset()
  669.             raise 
  670.  
  671.         fragment = self.fragment
  672.         self.reset()
  673.         return fragment
  674.  
  675.     
  676.     def _getDeclarations(self):
  677.         """Re-create the internal subset from the DocumentType node.
  678.  
  679.         This is only needed if we don't already have the
  680.         internalSubset as a string.
  681.         """
  682.         doctype = self.context.ownerDocument.doctype
  683.         s = ''
  684.         if doctype:
  685.             for i in range(doctype.notations.length):
  686.                 notation = doctype.notations.item(i)
  687.                 if s:
  688.                     s = s + '\n  '
  689.                 
  690.                 s = '%s<!NOTATION %s' % (s, notation.nodeName)
  691.                 if notation.publicId:
  692.                     s = '%s PUBLIC "%s"\n             "%s">' % (s, notation.publicId, notation.systemId)
  693.                     continue
  694.                 s = '%s SYSTEM "%s">' % (s, notation.systemId)
  695.             
  696.             for i in range(doctype.entities.length):
  697.                 entity = doctype.entities.item(i)
  698.                 if s:
  699.                     s = s + '\n  '
  700.                 
  701.                 s = '%s<!ENTITY %s' % (s, entity.nodeName)
  702.                 if entity.publicId:
  703.                     s = '%s PUBLIC "%s"\n             "%s"' % (s, entity.publicId, entity.systemId)
  704.                 elif entity.systemId:
  705.                     s = '%s SYSTEM "%s"' % (s, entity.systemId)
  706.                 else:
  707.                     s = '%s "%s"' % (s, entity.firstChild.data)
  708.                 if entity.notationName:
  709.                     s = '%s NOTATION %s' % (s, entity.notationName)
  710.                 
  711.                 s = s + '>'
  712.             
  713.         
  714.         return s
  715.  
  716.     
  717.     def _getNSattrs(self):
  718.         return ''
  719.  
  720.     
  721.     def external_entity_ref_handler(self, context, base, systemId, publicId):
  722.         if systemId == _FRAGMENT_BUILDER_INTERNAL_SYSTEM_ID:
  723.             old_document = self.document
  724.             old_cur_node = self.curNode
  725.             parser = self._parser.ExternalEntityParserCreate(context)
  726.             self.document = self.originalDocument
  727.             self.fragment = self.document.createDocumentFragment()
  728.             self.curNode = self.fragment
  729.             
  730.             try:
  731.                 parser.Parse(self._source, 1)
  732.             finally:
  733.                 self.curNode = old_cur_node
  734.                 self.document = old_document
  735.                 self._source = None
  736.  
  737.             return -1
  738.         else:
  739.             return ExpatBuilder.external_entity_ref_handler(self, context, base, systemId, publicId)
  740.  
  741.  
  742.  
  743. class Namespaces:
  744.     '''Mix-in class for builders; adds support for namespaces.'''
  745.     
  746.     def _initNamespaces(self):
  747.         self._ns_ordered_prefixes = []
  748.  
  749.     
  750.     def createParser(self):
  751.         '''Create a new namespace-handling parser.'''
  752.         parser = expat.ParserCreate(namespace_separator = ' ')
  753.         parser.namespace_prefixes = True
  754.         return parser
  755.  
  756.     
  757.     def install(self, parser):
  758.         '''Insert the namespace-handlers onto the parser.'''
  759.         ExpatBuilder.install(self, parser)
  760.         if self._options.namespace_declarations:
  761.             parser.StartNamespaceDeclHandler = self.start_namespace_decl_handler
  762.         
  763.  
  764.     
  765.     def start_namespace_decl_handler(self, prefix, uri):
  766.         '''Push this namespace declaration on our storage.'''
  767.         self._ns_ordered_prefixes.append((prefix, uri))
  768.  
  769.     
  770.     def start_element_handler(self, name, attributes):
  771.         if ' ' in name:
  772.             (uri, localname, prefix, qname) = _parse_ns_name(self, name)
  773.         else:
  774.             uri = EMPTY_NAMESPACE
  775.             qname = name
  776.             localname = None
  777.             prefix = EMPTY_PREFIX
  778.         node = minidom.Element(qname, uri, prefix, localname)
  779.         node.ownerDocument = self.document
  780.         _append_child(self.curNode, node)
  781.         self.curNode = node
  782.         if self._ns_ordered_prefixes:
  783.             for prefix, uri in self._ns_ordered_prefixes:
  784.                 if prefix:
  785.                     a = minidom.Attr(_intern(self, 'xmlns:' + prefix), XMLNS_NAMESPACE, prefix, 'xmlns')
  786.                 else:
  787.                     a = minidom.Attr('xmlns', XMLNS_NAMESPACE, 'xmlns', EMPTY_PREFIX)
  788.                 d = a.childNodes[0].__dict__
  789.                 d['data'] = d['nodeValue'] = uri
  790.                 d = a.__dict__
  791.                 d['value'] = d['nodeValue'] = uri
  792.                 d['ownerDocument'] = self.document
  793.                 _set_attribute_node(node, a)
  794.             
  795.             del self._ns_ordered_prefixes[:]
  796.         
  797.         if attributes:
  798.             _attrs = node._attrs
  799.             _attrsNS = node._attrsNS
  800.             for i in range(0, len(attributes), 2):
  801.                 aname = attributes[i]
  802.                 value = attributes[i + 1]
  803.                 if ' ' in aname:
  804.                     (uri, localname, prefix, qname) = _parse_ns_name(self, aname)
  805.                     a = minidom.Attr(qname, uri, localname, prefix)
  806.                     _attrs[qname] = a
  807.                     _attrsNS[(uri, localname)] = a
  808.                 else:
  809.                     a = minidom.Attr(aname, EMPTY_NAMESPACE, aname, EMPTY_PREFIX)
  810.                     _attrs[aname] = a
  811.                     _attrsNS[(EMPTY_NAMESPACE, aname)] = a
  812.                 d = a.childNodes[0].__dict__
  813.                 d['data'] = d['nodeValue'] = value
  814.                 d = a.__dict__
  815.                 d['ownerDocument'] = self.document
  816.                 d['value'] = d['nodeValue'] = value
  817.                 d['ownerElement'] = node
  818.             
  819.         
  820.  
  821.     if __debug__:
  822.         
  823.         def end_element_handler(self, name):
  824.             curNode = self.curNode
  825.             if ' ' in name:
  826.                 (uri, localname, prefix, qname) = _parse_ns_name(self, name)
  827.                 if not curNode.namespaceURI == uri and curNode.localName == localname or curNode.prefix == prefix:
  828.                     raise AssertionError, 'element stack messed up! (namespace)'
  829.             elif not curNode.nodeName == name:
  830.                 raise AssertionError, 'element stack messed up - bad nodeName'
  831.             if not curNode.namespaceURI == EMPTY_NAMESPACE:
  832.                 raise AssertionError, 'element stack messed up - bad namespaceURI'
  833.             self.curNode = curNode.parentNode
  834.             self._finish_end_element(curNode)
  835.  
  836.     
  837.  
  838.  
  839. class ExpatBuilderNS(Namespaces, ExpatBuilder):
  840.     '''Document builder that supports namespaces.'''
  841.     
  842.     def reset(self):
  843.         ExpatBuilder.reset(self)
  844.         self._initNamespaces()
  845.  
  846.  
  847.  
  848. class FragmentBuilderNS(Namespaces, FragmentBuilder):
  849.     '''Fragment builder that supports namespaces.'''
  850.     
  851.     def reset(self):
  852.         FragmentBuilder.reset(self)
  853.         self._initNamespaces()
  854.  
  855.     
  856.     def _getNSattrs(self):
  857.         '''Return string of namespace attributes from this element and
  858.         ancestors.'''
  859.         attrs = ''
  860.         context = self.context
  861.         L = []
  862.         while context:
  863.             if hasattr(context, '_ns_prefix_uri'):
  864.                 for prefix, uri in context._ns_prefix_uri.items():
  865.                     if prefix in L:
  866.                         continue
  867.                     
  868.                     L.append(prefix)
  869.                     if prefix:
  870.                         declname = 'xmlns:' + prefix
  871.                     else:
  872.                         declname = 'xmlns'
  873.                     if attrs:
  874.                         attrs = "%s\n    %s='%s'" % (attrs, declname, uri)
  875.                         continue
  876.                     attrs = " %s='%s'" % (declname, uri)
  877.                 
  878.             
  879.             context = context.parentNode
  880.         return attrs
  881.  
  882.  
  883.  
  884. class ParseEscape(Exception):
  885.     '''Exception raised to short-circuit parsing in InternalSubsetExtractor.'''
  886.     pass
  887.  
  888.  
  889. class InternalSubsetExtractor(ExpatBuilder):
  890.     '''XML processor which can rip out the internal document type subset.'''
  891.     subset = None
  892.     
  893.     def getSubset(self):
  894.         '''Return the internal subset as a string.'''
  895.         return self.subset
  896.  
  897.     
  898.     def parseFile(self, file):
  899.         
  900.         try:
  901.             ExpatBuilder.parseFile(self, file)
  902.         except ParseEscape:
  903.             pass
  904.  
  905.  
  906.     
  907.     def parseString(self, string):
  908.         
  909.         try:
  910.             ExpatBuilder.parseString(self, string)
  911.         except ParseEscape:
  912.             pass
  913.  
  914.  
  915.     
  916.     def install(self, parser):
  917.         parser.StartDoctypeDeclHandler = self.start_doctype_decl_handler
  918.         parser.StartElementHandler = self.start_element_handler
  919.  
  920.     
  921.     def start_doctype_decl_handler(self, name, publicId, systemId, has_internal_subset):
  922.         if has_internal_subset:
  923.             parser = self.getParser()
  924.             self.subset = []
  925.             parser.DefaultHandler = self.subset.append
  926.             parser.EndDoctypeDeclHandler = self.end_doctype_decl_handler
  927.         else:
  928.             raise ParseEscape()
  929.  
  930.     
  931.     def end_doctype_decl_handler(self):
  932.         s = ''.join(self.subset).replace('\r\n', '\n').replace('\r', '\n')
  933.         self.subset = s
  934.         raise ParseEscape()
  935.  
  936.     
  937.     def start_element_handler(self, name, attrs):
  938.         raise ParseEscape()
  939.  
  940.  
  941.  
  942. def parse(file, namespaces = 1):
  943.     """Parse a document, returning the resulting Document node.
  944.  
  945.     'file' may be either a file name or an open file object.
  946.     """
  947.     if namespaces:
  948.         builder = ExpatBuilderNS()
  949.     else:
  950.         builder = ExpatBuilder()
  951.     if isinstance(file, StringTypes):
  952.         fp = open(file, 'rb')
  953.         
  954.         try:
  955.             result = builder.parseFile(fp)
  956.         finally:
  957.             fp.close()
  958.  
  959.     else:
  960.         result = builder.parseFile(file)
  961.     return result
  962.  
  963.  
  964. def parseString(string, namespaces = 1):
  965.     '''Parse a document from a string, returning the resulting
  966.     Document node.
  967.     '''
  968.     if namespaces:
  969.         builder = ExpatBuilderNS()
  970.     else:
  971.         builder = ExpatBuilder()
  972.     return builder.parseString(string)
  973.  
  974.  
  975. def parseFragment(file, context, namespaces = 1):
  976.     """Parse a fragment of a document, given the context from which it
  977.     was originally extracted.  context should be the parent of the
  978.     node(s) which are in the fragment.
  979.  
  980.     'file' may be either a file name or an open file object.
  981.     """
  982.     if namespaces:
  983.         builder = FragmentBuilderNS(context)
  984.     else:
  985.         builder = FragmentBuilder(context)
  986.     if isinstance(file, StringTypes):
  987.         fp = open(file, 'rb')
  988.         
  989.         try:
  990.             result = builder.parseFile(fp)
  991.         finally:
  992.             fp.close()
  993.  
  994.     else:
  995.         result = builder.parseFile(file)
  996.     return result
  997.  
  998.  
  999. def parseFragmentString(string, context, namespaces = 1):
  1000.     '''Parse a fragment of a document from a string, given the context
  1001.     from which it was originally extracted.  context should be the
  1002.     parent of the node(s) which are in the fragment.
  1003.     '''
  1004.     if namespaces:
  1005.         builder = FragmentBuilderNS(context)
  1006.     else:
  1007.         builder = FragmentBuilder(context)
  1008.     return builder.parseString(string)
  1009.  
  1010.  
  1011. def makeBuilder(options):
  1012.     '''Create a builder based on an Options object.'''
  1013.     if options.namespaces:
  1014.         return ExpatBuilderNS(options)
  1015.     else:
  1016.         return ExpatBuilder(options)
  1017.  
  1018.